package com.youdoneed.user.focusregion;

import com.querydsl.sql.SQLQueryFactory;
import com.querydsl.sql.dml.SQLInsertClause;
import com.youdoneed.base.application.AppException;
import com.youdoneed.base.common.GlobalIdWorker;
import com.youdoneed.user.model.FocusRegion;
import com.youdoneed.user.query.QFocusRegion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 关注区域服务实现类。
 *
 * @author Ewing
 * @date 2017.2.8
 */
@Service
@Transactional
public class FocusRegionServiceImpl implements FocusRegionService {
    private final Logger logger = LoggerFactory.getLogger(FocusRegionServiceImpl.class);

    @Autowired
    private SQLQueryFactory queryFactory;

    private QFocusRegion qFocusRegion = QFocusRegion.FocusRegion;

    public static final int MAX_FOCUS_REGION = 6;

    /**
     * 添加关注区域。
     */
    @Override
    public FocusRegion addFocusRegion(FocusRegion focusRegion) {
        if (focusRegion == null || !StringUtils.hasText(focusRegion.getUserId())
                || focusRegion.getLongitude() == null || focusRegion.getLatitude() == null
                || !StringUtils.hasText(focusRegion.getName())) {
            throw new AppException("FocusRegion info is empty.");
        }
        // 限制不超过最大数量
        if (queryFactory.selectFrom(qFocusRegion)
                .where(qFocusRegion.focusRegionId.eq(focusRegion.getUserId()))
                .fetchCount() >= MAX_FOCUS_REGION) {
            throw new AppException("FocusRegion is up to maximum.");
        }
        // 初始化默认值并新增
        if (focusRegion.getCheckState() == null) {
            focusRegion.setCheckState(0);
        }
        focusRegion.setLongitude(new BigDecimal(focusRegion.getLongitude())
                .setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue());
        focusRegion.setLatitude(new BigDecimal(focusRegion.getLatitude())
                .setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue());
        focusRegion.setFocusRegionId(GlobalIdWorker.nextString());
        focusRegion.setCreateTime(new Date());
        queryFactory.insert(qFocusRegion)
                .populate(focusRegion)
                .execute();
        return focusRegion;
    }

    /**
     * 根据ID获取关注区域。
     */
    @Override
    public FocusRegion getFocusRegion(String focusRegionId) {
        if (!StringUtils.hasText(focusRegionId)) {
            throw new AppException("FocusRegion id is empty.");
        }
        return queryFactory.selectFrom(qFocusRegion)
                .where(qFocusRegion.focusRegionId.eq(focusRegionId))
                .fetchOne();
    }

    /**
     * 获取用户的所有关注区域。
     */
    @Override
    public List<FocusRegion> userFocusRegions(String userId) {
        if (!StringUtils.hasText(userId)) {
            throw new AppException("User id is empty.");
        }
        return queryFactory.selectFrom(qFocusRegion)
                .where(qFocusRegion.userId.eq(userId))
                .fetch();
    }

    /**
     * 获取用户选择的关注区域。
     */
    @Override
    public FocusRegion checkedFocusRegion(String userId) {
        if (!StringUtils.hasText(userId)) {
            throw new AppException("User id is empty.");
        }
        return queryFactory.selectFrom(qFocusRegion)
                .where(qFocusRegion.userId.eq(userId))
                .where(qFocusRegion.checkState.eq(1))
                .fetchFirst();
    }

    /**
     * 删除关注区域。
     */
    @Override
    public long deleteFocusRegion(String focusRegionId) {
        if (!StringUtils.hasText(focusRegionId)) {
            throw new AppException("FocusRegion id is empty.");
        }
        return queryFactory.delete(qFocusRegion)
                .where(qFocusRegion.focusRegionId.eq(focusRegionId))
                .execute();
    }

    /**
     * 更新关注区域。
     */
    @Override
    public FocusRegion updateFocusRegion(FocusRegion focusRegion) {
        if (focusRegion == null || !StringUtils.hasText(focusRegion.getFocusRegionId())) {
            throw new AppException("FocusRegion info is empty.");
        }
        FocusRegion update = new FocusRegion();
        update.setFocusRegionId(focusRegion.getFocusRegionId());
        if (StringUtils.hasText(focusRegion.getName())) {
            update.setName(focusRegion.getName());
        }
        if (focusRegion.getLongitude() != null) {
            update.setLongitude(focusRegion.getLongitude());
        }
        if (focusRegion.getLatitude() != null) {
            update.setLatitude(focusRegion.getLatitude());
        }
        if (focusRegion.getCheckState() != null) {
            update.setCheckState(focusRegion.getCheckState());
        }
        queryFactory.update(qFocusRegion).populate(update)
                .where(qFocusRegion.focusRegionId.eq(update.getFocusRegionId()))
                .execute();
        return update;
    }

    @Override
    public long setUserFocusRegions(String userId, FocusRegion[] focusRegions) {
        if (!StringUtils.hasText(userId)) {
            throw new AppException("UserInformationIsEmpty");
        }
        queryFactory.delete(qFocusRegion)
                .where(qFocusRegion.userId.eq(userId))
                .execute();
        if (focusRegions == null || focusRegions.length < 1) {
            return 0L;
        }
        SQLInsertClause insert = queryFactory.insert(qFocusRegion);
        for (int i = 0; i < focusRegions.length && i < MAX_FOCUS_REGION; i++) {
            FocusRegion focusRegion = focusRegions[i];
            if (focusRegion == null || !StringUtils.hasText(focusRegion.getName())
                    || focusRegion.getLongitude() == null || focusRegion.getLatitude() == null) {
                throw new AppException("FocusRegion info is empty.");
            }
            focusRegion.setFocusRegionId(GlobalIdWorker.nextString());
            focusRegion.setUserId(userId);
            focusRegion.setCreateTime(new Date());
            insert.populate(focusRegion)
                    .addBatch();
        }
        return insert.isEmpty() ? 0L : insert.execute();
    }

}
